package com.eian.boot.common.core.utils;

import com.eian.boot.common.core.exception.SystemException;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * spring el表达式解析
 *
 * @author alex.meng
 * @createTime 2023-06-21 15:00
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class SpElUtils {

    private static final ExpressionParser SPEL_EXPRESSION_PARSER = new SpelExpressionParser();
    private static final DefaultParameterNameDiscoverer DEFAULT_PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
    private static final String LOG_TEMPLATE = "[ spEl 解析内容 ]: {}";

    public static String parseSpEl(Method method, Object[] args, String spEl) {
        // 解析参数名
        String[] params = Optional.ofNullable(DEFAULT_PARAMETER_NAME_DISCOVERER.getParameterNames(method)).orElse(new String[]{});
        // EL解析需要的上下文对象
        EvaluationContext context = createEvaluationContext(params, args);

        Expression expression = SPEL_EXPRESSION_PARSER.parseExpression(spEl);
        String expressionValue;
        try {
            expressionValue = expression.getValue(context, String.class);
        } catch (Exception e) {
            log.error("Error parsing SpEL: ", e);
            throw new SystemException(e.getMessage());
        }
        log.debug(LOG_TEMPLATE, expressionValue);
        return expressionValue;
    }

    public static Map<String, String> parseSpEls(Method method, Object[] args, String spEl) {
        // 解析参数名
        String[] params = Optional.ofNullable(DEFAULT_PARAMETER_NAME_DISCOVERER.getParameterNames(method)).orElse(new String[]{});
        // EL解析需要的上下文对象
        EvaluationContext context = createEvaluationContext(params, args);

        String[] spElItems = spEl.split(",");
        Map<String, String> spelMap = new HashMap<>(spElItems.length);
        for (String item : spElItems) {
            Expression expression = SPEL_EXPRESSION_PARSER.parseExpression(item);
            String expressionValue;
            try {
                expressionValue = expression.getValue(context, String.class);
            } catch (Exception e) {
                log.error("Error parsing SpEL item: {}", item, e);
                throw new SystemException(e.getMessage());
            }
            spelMap.put(item, expressionValue);
            log.debug("[ item - spEl 解析内容 ]:{} - {}", item, expressionValue);
        }
        return spelMap;
    }

    public static String getMethodKey(Method method) {
        return method.getDeclaringClass().getName() + "#" + method.getName();
    }

    private static EvaluationContext createEvaluationContext(String[] params, Object[] args) {
        EvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < params.length; i++) {
            context.setVariable(params[i], args[i]);
        }
        return context;
    }
}
